#include <stdlib.h>
#include <stdint.h>
#include "hashlib.h"

HASH(*getHashCode)
(const uint8_t *byteStream, unsigned int len) = BKDRHash;

HASH(*getHashCodeS)
(const char *byteStream) = (HASH(*)(const char*))BKDRHashS;

HASH RSHash(const uint8_t *str, unsigned int len)
{
    HASH b = 378551;
    HASH a = 63689;
    HASH hash = 0;
    HASH i = 0;

    for (i = 0; i < len; str++, i++)
    {
        hash = hash * a + (*str);
        a = a * b;
    }

    return hash;
}
/* End Of RS Hash Function */

HASH JSHash(const uint8_t *str, unsigned int len)
{
    HASH hash = 1315423911;
    HASH i = 0;

    for (i = 0; i < len; str++, i++)
    {
        hash ^= ((hash << 5) + (*str) + (hash >> 2));
    }

    return hash;
}
/* End Of JS Hash Function */

HASH PJWHash(const uint8_t *str, unsigned int len)
{
    const HASH BitsInUnsignedInt = (HASH)(sizeof(HASH) * 8);
    const HASH ThreeQuarters = (HASH)((BitsInUnsignedInt * 3) / 4);
    const HASH OneEighth = (HASH)(BitsInUnsignedInt / 8);
    const HASH HighBits = (HASH)(0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth);
    HASH hash = 0;
    HASH test = 0;
    HASH i = 0;

    for (i = 0; i < len; str++, i++)
    {
        hash = (hash << OneEighth) + (*str);

        if ((test = hash & HighBits) != 0)
        {
            hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
        }
    }

    return hash;
}
/* End Of  P. J. Weinberger Hash Function */

HASH ELFHash(const uint8_t *str, unsigned int len)
{
    HASH hash = 0;
    HASH x = 0;
    HASH i = 0;

    for (i = 0; i < len; str++, i++)
    {
        hash = (hash << 4) + (*str);
        if ((x = hash & 0xF0000000L) != 0)
        {
            hash ^= (x >> 24);
        }
        hash &= ~x;
    }

    return hash;
}
/* End Of ELF Hash Function */

HASH BKDRHash(const uint8_t *str, unsigned int len)
{
    HASH seed = 131; /* 31 131 1313 13131 131313 etc.. */
    HASH hash = 0;
    HASH i = 0;

    for (i = 0; i < len; str++, i++)
    {
        hash = (hash * seed) + (*str);
    }

    return hash;
}
/* End Of BKDR Hash Function */

HASH SDBMHash(const uint8_t *str, unsigned int len)
{
    HASH hash = 0;
    HASH i = 0;

    for (i = 0; i < len; str++, i++)
    {
        hash = (*str) + (hash << 6) + (hash << 16) - hash;
    }

    return hash;
}
/* End Of SDBM Hash Function */

HASH DJBHash(const uint8_t *str, unsigned int len)
{
    HASH hash = 5381;
    HASH i = 0;

    for (i = 0; i < len; str++, i++)
    {
        hash = ((hash << 5) + hash) + (*str);
    }

    return hash;
}
/* End Of DJB Hash Function */

HASH DEKHash(const uint8_t *str, unsigned int len)
{
    HASH hash = len;
    HASH i = 0;

    for (i = 0; i < len; str++, i++)
    {
        hash = ((hash << 5) ^ (hash >> 27)) ^ (*str);
    }
    return hash;
}
/* End Of DEK Hash Function */

HASH BPHash(const uint8_t *str, unsigned int len)
{
    HASH hash = 0;
    HASH i = 0;
    for (i = 0; i < len; str++, i++)
    {
        hash = hash << 7 ^ (*str);
    }

    return hash;
}
/* End Of BP Hash Function */

HASH FNVHash(const uint8_t *str, unsigned int len)
{
    const HASH fnv_prime = 0x811C9DC5;
    HASH hash = 0;
    HASH i = 0;

    for (i = 0; i < len; str++, i++)
    {
        hash *= fnv_prime;
        hash ^= (*str);
    }

    return hash;
}
/* End Of FNV Hash Function */

HASH APHash(const uint8_t *str, unsigned int len)
{
    HASH hash = 0xAAAAAAAA;
    HASH i;
    if (len)
    {
        hash ^= ((hash << 7) ^ (*str++) * (hash >> 3));
    }
    for (i = 1; i < len; str++, i++)
    {
        hash ^= (~((hash << 11) + ((*str) ^ (hash >> 5))));
    }

    return hash;
}
/* End Of AP Hash Function */

//------------------------------------------------------
HASH SDBMHashS(const uint8_t *str)
{
    HASH hash = 0;

    while (*str)
    {
        // equivalent to: hash = 65599*hash + (*str++);
        hash = (*str++) + (hash << 6) + (hash << 16) - hash;
    }

    return hash;
}

// RS Hash Function
HASH RSHashS(const uint8_t *str)
{
    HASH b = 378551;
    HASH a = 63689;
    HASH hash = 0;

    while (*str)
    {
        hash = hash * a + (*str++);
        a *= b;
    }

    return hash;
}

// JS Hash Function
HASH JSHashS(const uint8_t *str)
{
    HASH hash = 1315423911;

    while (*str)
    {
        hash ^= ((hash << 5) + (*str++) + (hash >> 2));
    }

    return hash;
}

// P. J. Weinberger Hash Function
HASH PJWHashS(const uint8_t *str)
{
    HASH BitsInUnignedInt = (HASH)(sizeof(HASH) * 8);
    HASH ThreeQuarters = (HASH)((BitsInUnignedInt * 3) / 4);
    HASH OneEighth = (HASH)(BitsInUnignedInt / 8);
    HASH HighBits = (HASH)(0xFFFFFFFF) << (BitsInUnignedInt - OneEighth);
    HASH hash = 0;
    HASH test = 0;

    while (*str)
    {
        hash = (hash << OneEighth) + (*str++);
        if ((test = hash & HighBits) != 0)
        {
            hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
        }
    }

    return hash;
}

// ELF Hash Function
HASH ELFHashS(const uint8_t *str)
{
    HASH hash = 0;
    HASH x = 0;

    while (*str)
    {
        hash = (hash << 4) + (*str++);
        if ((x = hash & 0xF0000000L) != 0)
        {
            hash ^= (x >> 24);
            hash &= ~x;
        }
    }

    return hash;
}

// BKDR Hash Function
HASH BKDRHashS(const uint8_t *str)
{
    HASH seed = 131; // 31 131 1313 13131 131313 etc..
    HASH hash = 0;

    while (*str)
    {
        hash = hash * seed + (*str++);
    }

    return hash;
}

// DJB Hash Function
HASH DJBHashS(const uint8_t *str)
{
    HASH hash = 5381;

    while (*str)
    {
        hash += (hash << 5) + (*str++);
    }

    return hash;
}

// AP Hash Function
HASH APHashS(const uint8_t *str)
{
    HASH hash = 0;
    int i;
    if (*str)
    {
        hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3));
    }

    for (i = 1; *str; i++)
    {
        hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5)));
    }

    return hash;
}